﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using MSWebBroswerEx;

namespace MSWebBrowserEx
{
    public class WebTaskManager : IDisposable
    {
        static object locker = new object();
        private List<WebBrowserEx> webBroswers = new List<WebBrowserEx>();
        private int _threadCount = 1;
        private int _interval = 3000;
        #region delegate /Events declare
        public delegate void WebBrowserTaskCompletedEventHandler(string key);
        public event WebBrowserTaskCompletedEventHandler WebBrowserTaskCompletedEvent;

        public delegate void DocumentStatusChangedEventHandler(string key ,WebBrowserReadyState currentStatus);
        public event DocumentStatusChangedEventHandler DocumentStatusChangedEvent;

        public delegate void DocumentTitleShownEventHandler(string key, string title);
        public event DocumentTitleShownEventHandler DocumentTitleShownEvent;

        public delegate void MemoryOverflowEventHandler(string key);
        public event MemoryOverflowEventHandler MemoryOverflowEvent;

        public delegate void ErrorEventHandler(string key, string detail);
        public event ErrorEventHandler ErrorEvent;

        #endregion

        private Dictionary<string, WebBrowserTask> _task = new Dictionary<string, WebBrowserTask>();
        public Dictionary<string, WebBrowserTask> Tasks
        {
            get
            {
                return _task;
            }
            set
            {
                _task = value;
            }
        }
        public void ClearAllTask()
        {
            lock (locker )
            {
                _task.Clear();
            }
        }
        public WebTaskManager(int threadCount ,int timerInterval = 3000 )
        {
            _threadCount = threadCount;
            _interval = timerInterval;
            GenerateBroswerCache();
            //load IE Proxy 
            ProxyHelper hp = new ProxyHelper();
            string proxyStr = hp.GetProxyString();
            if (!string.IsNullOrWhiteSpace(proxyStr))
            {
                hp.RefreshIESettings(proxyStr);
            }
        }
        public void Reboot()
        {
            List<string> processingKeys = new List<string>();
            lock (locker)
            {
                
                for (int i = 0; i < webBroswers.Count; i++)
                {
                    WebBrowserEx wx = webBroswers[i];
                    processingKeys.Add( wx.Key );
                    wx.Stop();
                    wx.Dispose();
                }
                this.webBroswers = new List<WebBrowserEx>();
            }
            foreach (string key in processingKeys)
            {
                ChangeTaskStatus(key, TaskStatusEx.NA);
            }
            this.GenerateBroswerCache();
            this.LoopIdleWebBrowser();
        }
        void GenerateBroswerCache()
        {
            //创建WebBroswer Object
            for (int i = 0; i < _threadCount; i++)
            {
                this.webBroswers.Add(new WebBrowserEx() { Internval = _interval });
            }
            foreach (WebBrowserEx wb in this.webBroswers)
            {
                wb.DocumentCompletedEvent += wb_DocumentCompletedEvent;
                wb.DocumentStatusChangedEvent += wb_DocumentStatusChangedEvent;
                wb.DocumentTitleShownEvent += wb_DocumentTitleShownEvent;
                wb.MemoryOverflowEvent += wb_MemoryOverflowEvent;
                wb.ErrorEvent += wb_ErrorEvent;
            }
        }

        void wb_ErrorEvent(string key, string detail)
        {
            ChangeTaskStatus(key, TaskStatusEx.Error);
            if (ErrorEvent != null)
            {
                ErrorEvent(key, detail);
            }
            this.LoopIdleWebBrowser();
        }
        void wb_MemoryOverflowEvent(string key)
        {
            //throw new NotImplementedException();
            //内存溢出
            lock (locker)
            {
                for (int i=0;i<webBroswers.Count;i++ )
                {
                    WebBrowserEx wx = webBroswers[i];
                    if (wx.Key.Equals(key))
                    {
                        wx = null;
                        wx = new WebBrowserEx() { Internval = _interval };
                        wx.DocumentCompletedEvent += wb_DocumentCompletedEvent;
                        wx.DocumentStatusChangedEvent += wb_DocumentStatusChangedEvent;
                        wx.DocumentTitleShownEvent += wb_DocumentTitleShownEvent;
                        wx.MemoryOverflowEvent += wb_MemoryOverflowEvent;
                        wx.ErrorEvent += wb_ErrorEvent;

                        wx.Stop();
                        wx.Dispose();
                    }
                }
            }
            ChangeTaskStatus(key, TaskStatusEx.NA);
            this.LoopIdleWebBrowser();
            //抛出错误
            if (MemoryOverflowEvent != null)
            {
                MemoryOverflowEvent(key);
            }
        }
        
        void wb_DocumentTitleShownEvent(string key, string title)
        {
            if (DocumentTitleShownEvent != null)
            {
                DocumentTitleShownEvent(key, title);
            }
        }
       
        public void Start()
        {
            LoopIdleWebBrowser();
        }

        public void RetestTask(string taskKey)
        {
            
            lock (locker)
            {
                for (int i = 0; i < webBroswers.Count; i++)
                {
                    WebBrowserEx wx = webBroswers[i];
                    if (wx.Key.Equals(taskKey))
                    {
                        wx.Stop();
                    }
                }
            }
            ChangeTaskStatus(taskKey, TaskStatusEx.NA);

            LoopIdleWebBrowser();
        }
        void LoopIdleWebBrowser()
        { 
            //轮循Web Broswer，寻找下一个空闲的
            lock (locker)
            {
                foreach (KeyValuePair<string ,WebBrowserTask> task in this.Tasks)
                {
                    if (task.Value.Status == TaskStatusEx.NA)
                    {
                        foreach (WebBrowserEx wbEx in this.webBroswers)
                        {
                            if (string.IsNullOrEmpty(wbEx.Key))
                            {
                                //锁定当前Web Broswer
                                lock (locker)
                                {
                                    //更新状态
                                    task.Value.Status = TaskStatusEx.Processing;
                                    wbEx.OpenUrl(task.Value.Url, task.Value.Key);
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }
        void ChangeTaskStatus(string key, TaskStatusEx status)
        {
            lock (locker)
            {
                foreach (KeyValuePair<string, WebBrowserTask> task in this.Tasks)
                {
                    if (task.Key.Equals(key, StringComparison.CurrentCultureIgnoreCase))
                    {
                        task.Value.Status = status;
                    }
                }
            }
        }
        void wb_DocumentStatusChangedEvent(string key ,System.Windows.Forms.WebBrowserReadyState currentStatus)
        {
            if (DocumentStatusChangedEvent != null)
            {
                DocumentStatusChangedEvent(key , currentStatus);
            }
        }

        void wb_DocumentCompletedEvent(string key, string htmlString, Bitmap img)
        {
            //throw new NotImplementedException();
            string fullPath = string.Empty;
            lock (locker)
            {
                if (Tasks.ContainsKey(key))
                {
                    WebBrowserTask ts = Tasks[key];
                    if (string.IsNullOrEmpty(ts.ImageFullPath))
                    {
                        ts.ImageFullPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, Guid.NewGuid().ToString() + ".jpg");
                    }
                    fullPath = ts.ImageFullPath;
                }
            }
            //开始保存图片
            try
            {
                img.Save(fullPath, System.Drawing.Imaging.ImageFormat.Jpeg);
                //开始下一任务
                ChangeTaskStatus(key, TaskStatusEx.Completed);
                //触发完成事件
                if (WebBrowserTaskCompletedEvent != null)
                {
                    WebBrowserTaskCompletedEvent(key);
                }
            }
            catch (Exception ex)
            {
                ChangeTaskStatus(key, TaskStatusEx.NA );
                if (ErrorEvent != null)
                {
                    ErrorEvent(key, string.Format("Save image error ,detail : {0}" ,ex.ToString() ));
                }
            }
            finally
            {
                img.Dispose();
            }

            LoopIdleWebBrowser();
            
        }

        public void Dispose()
        {
            //disppose the webbrowser object 
        }
    }
}
